package usuarios;

import exceptions.BairroInvalidoException;
import exceptions.CEPInvalidoException;
import exceptions.LogradouroInvalidoException;
import exceptions.NumeroInvalidoException;

public class Endereco {
	private static final String REGEX_LOGRADOURO = "..*";
	private static final String REGEX_NUMERO = "\\d+\\w{0,1}";
	private static final String REGEX_BAIRRO = "..*";
	private static final String REGEX_CEP = "\\d{5}-\\d{3}|\\d{8}";
	private String logradouro;
	private String numero;
	private String bairro;
	private String cep;
	private boolean principal;

	/**
	 * Contrutor de um endereco.
	 * 
	 * @param logradouro
	 *            O logradouro. Este nao pode ser nulo e deve ser formado apenas
	 *            por letras
	 * @param numero
	 *            O numero. Este nao pode ser nulo e deve ser formado por
	 *            digitos ou inicialmente por digitos e finalizado com uma
	 *            letra.
	 * @param bairro
	 *            O bairro. Este nao pode ser nulo e deve ser formado apenas por
	 *            letras.
	 * @param cep
	 *            O CEP. Este nao pode ser nulo e deve ser formado por 7 digitos
	 *            ou 7 digitos com um hifen apos o quarto digito.
	 * @param principal
	 *            Boolean indicando se este endereco eh principal ou nao.
	 * @throws LogradouroInvalidoException
	 *             Se for nulo ou nao ser ser formado apenas por letras.
	 * @throws NumeroInvalidoException
	 *             Se for nulo ou nao for formado por digitos ou inicialmente
	 *             formado por digitos e finalizado com uma letra.
	 * @throws BairroInvalidoException
	 *             Se for nulo ou nao for formado apenas por letras.
	 * @throws CEPInvalidoException
	 *             Se for nulo ou nao for formado por 7 digitos ou 7 digitos com
	 *             um hifen apos o quarto digito.
	 */
	public Endereco(String logradouro, String numero, String bairro,
			String cep, boolean principal) throws LogradouroInvalidoException,
			NumeroInvalidoException, BairroInvalidoException,
			CEPInvalidoException {
		if (logradouro == null || !logradouro.matches(REGEX_LOGRADOURO))
			throw new LogradouroInvalidoException();
		if (numero == null || !numero.matches(REGEX_NUMERO))
			throw new NumeroInvalidoException();
		if (bairro == null || !bairro.matches(REGEX_BAIRRO))
			throw new BairroInvalidoException();
		if (cep == null || !cep.matches(REGEX_CEP))
			throw new CEPInvalidoException();
		this.logradouro = logradouro;
		this.numero = numero;
		this.bairro = bairro;
		this.cep = cep;
		this.principal = principal;
	}

	/**
	 * Recupera o logradouro.
	 * 
	 * @return O logradouro.
	 */
	public String getLogradouro() {
		return logradouro;
	}

	/**
	 * Edita o logradouro.
	 * 
	 * @param logradouro
	 *            O novo logradouro.
	 */
	public void setLogradouro(String logradouro) {
		this.logradouro = logradouro;
	}

	/**
	 * Recupera o número da casa.
	 * 
	 * @return O número da casa.
	 */
	public String getNumero() {
		return numero;
	}

	/**
	 * Edita o número da casa.
	 * 
	 * @param numero
	 *            O novo número da casa.
	 */
	public void setNumero(String numero) {
		this.numero = numero;
	}

	/**
	 * Recupera o bairro.
	 * 
	 * @return O bairro.
	 */
	public String getBairro() {
		return bairro;
	}

	/**
	 * Edita o bairro.
	 * 
	 * @param bairro
	 *            O novo bairro.
	 */
	public void setBairro(String bairro) {
		this.bairro = bairro;
	}

	/**
	 * Recupera o CEP.
	 * 
	 * @return O CEP.
	 */
	public String getCep() {
		return cep;
	}

	/**
	 * Edita o CEP.
	 * 
	 * @param cep
	 *            O novo CEP .
	 */
	public void setCep(String cep) {
		this.cep = cep;
	}

	/**
	 * Verifica se o endereco eh o principal.
	 * 
	 * @return true, se o endereco for o principal, e false, caso contrario.
	 */
	public boolean isPrincipal() {
		return principal;
	}

	/**
	 * Edita o valor de endereco principal.
	 * 
	 * @param principal
	 *            true, se este endereco agora eh o principal, ou false, caso
	 *            tenha perdido a propriedade de ser o endereco principal.
	 */
	public void setPrincipal(boolean principal) {
		this.principal = principal;
	}

	/**
	 * Calcula o valor HashCode do objeto.
	 * 
	 * @return O valor HashCode do objeto.
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((bairro == null) ? 0 : bairro.hashCode());
		result = prime * result + ((cep == null) ? 0 : cep.hashCode());
		result = prime * result
				+ ((logradouro == null) ? 0 : logradouro.hashCode());
		result = prime * result + ((numero == null) ? 0 : numero.hashCode());
		result = prime * result + (principal ? 1231 : 1237);
		return result;
	}

	/**
	 * Compara se o objeto recebido como parametro eh igual a este.
	 * 
	 * @return true, se o objeto recebido for igual a este, ou false, caso
	 *         contrario.
	 */
	@Override
	public boolean equals(Object obj) {
		if (!(obj instanceof Endereco)) {
			return false;
		}
		Endereco e = (Endereco) obj;
		return (e.getNumero().equals(getNumero()) && e.getCep()
				.equals(getCep()));
	}

	/**
	 * Representa em String o Endereco.
	 * 
	 * @return Representacao em String do Endereco.
	 */
	@Override
	public String toString() {
		return "Logradouro: " + logradouro + "\nNumero: " + numero
				+ "\nBairro: " + bairro + "\nCEP: " + cep + "\nPrincipal: "
				+ principal;
	}
}